package net.zoneland.zrdp.biz.service.impl;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.branchitech.account.ldap.UserBean;
import net.zoneland.uniflow.client.ReadObject;
import net.zoneland.uniflow.client.TaskObject;
import net.zoneland.uniflow.client.UserInfo;
import net.zoneland.zrdp.biz.common.CommonUtils;
import net.zoneland.zrdp.biz.common.Constants;
import net.zoneland.zrdp.biz.domain.FlowMainInfo;
import net.zoneland.zrdp.biz.domain.pojo.form.CreateReadsForm;
import net.zoneland.zrdp.biz.domain.pojo.form.StartProcessForm;
import net.zoneland.zrdp.biz.domain.pojo.form.TaskProcessForm;
import net.zoneland.zrdp.biz.enums.ExtendParamNameEnum;
import net.zoneland.zrdp.biz.mapstruct.FlowProcessConverter;
import net.zoneland.zrdp.biz.service.IFlowMainInfoService;
import net.zoneland.zrdp.common.core.domain.entity.SysUser;
import net.zoneland.zrdp.common.exception.BizException;
import net.zoneland.zrdp.common.utils.DateUtil;
import net.zoneland.zrdp.common.utils.SecurityUtils;
import net.zoneland.zrdp.framework.web.service.NotifyService;
import net.zoneland.zrdp.framework.web.service.uniflow.WorkFlowService;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.stereotype.Service;
import net.zoneland.zrdp.biz.mapper.FlowApproveInfoMapper;
import net.zoneland.zrdp.biz.domain.FlowApproveInfo;
import net.zoneland.zrdp.biz.service.IFlowApproveInfoService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 审批记录Service业务层处理
 *
 * @author zonevue
 */
@Service
public class FlowApproveInfoServiceImpl implements IFlowApproveInfoService {

    @Resource
    private FlowApproveInfoMapper flowApproveInfoMapper;

    @Resource
    private WorkFlowService workFlowService;

    @Resource
    private IFlowMainInfoService flowMainInfoService;

    @Resource
    private NotifyService notifyService;

    /** 默认草稿节点ID. **/
    private static final String DRAFT_NODE_ID = "draft";
    /** 默认草稿节点名称.**/
    private static final String DRAFT_NODE_NAME = "草稿";
    /** 默认草稿提交名称.**/
    private static final String DRAFT_NODE_OPTION = "暂存";
    /** 任务编码.**/
    private static final String TIID = "tiid";
    /** 人员ID.**/
    private static final String USER_ID = "userId";
    /** 人员名称.**/
    private static final String USER_NAME = "userName";
    /** 系统提交默认审批意见.**/
    private static final  String READY_NODE_JUMP_NOTION = "系统自动结束";
    /** 系统默认复活节点编码.**/
    private static final String RESURRECTION_ID = "resurrection";

    /**
     * 查询审批记录
     *
     * @param id 审批记录主键
     * @return 审批记录
     */
    @Override
    public FlowApproveInfo selectFlowApproveInfoById(final Long id) {
        return flowApproveInfoMapper.selectFlowApproveInfoById(id);
    }

    /**
     * 查询审批记录列表
     *
     * @param flowApproveInfo 审批记录
     * @return 审批记录
     */
    @Override
    public List<FlowApproveInfo> selectFlowApproveInfoList(final FlowApproveInfo flowApproveInfo) {
        return flowApproveInfoMapper.selectFlowApproveInfoList(flowApproveInfo);
    }

    @Override
    public List<FlowApproveInfo> getTaskFlowApproveByPiid(final String piid, final String deptName) {
        final FlowApproveInfo flowApproveInfo = new FlowApproveInfo();
        flowApproveInfo.setPiid(piid);
        flowApproveInfo.setHandlerDept(deptName);
        return flowApproveInfoMapper.selectFlowApproveInfoList(flowApproveInfo);
    }

    /**
     * 新增审批记录
     *
     * @param flowApproveInfo 审批记录
     * @return 结果
     */
    @Override
    public int insertFlowApproveInfo(final FlowApproveInfo flowApproveInfo) {
        flowApproveInfo.setCreateTime(DateUtil.getNowLocalDateTime());
        return flowApproveInfoMapper.insertFlowApproveInfo(flowApproveInfo);
    }

    /**
     * 修改审批记录
     *
     * @param flowApproveInfo 审批记录
     * @return 结果
     */
    @Override
    public int updateFlowApproveInfo(final FlowApproveInfo flowApproveInfo) {
        flowApproveInfo.setUpdateTime(DateUtil.getNowLocalDateTime());
        return flowApproveInfoMapper.updateFlowApproveInfo(flowApproveInfo);
    }

    /**
     * 批量删除审批记录
     *
     * @param ids 需要删除的审批记录主键
     * @return 结果
     */
    @Override
    public int deleteFlowApproveInfoByIds(final Long[] ids) {
        return flowApproveInfoMapper.deleteFlowApproveInfoByIds(ids);
    }

    /**
     * 删除审批记录信息
     *
     * @param id 审批记录主键
     * @return 结果
     */
    @Override
    public int deleteFlowApproveInfoById(final Long id) {
        return flowApproveInfoMapper.deleteFlowApproveInfoById(id);
    }
    /**
     * 获取任务编码、处理人ID、处理人名称，逗号拼接.
     * @param taskObjectList 任务实例对象（该对象本身不能为空，为空只能说明流程异常）.
     * @return org.apache.commons.lang3.tuple.Triple<java.lang.String,java.lang.String,java.lang.String>
     **/
    private Triple<String, String, String> getTiidAndUserIdAndUserName(final List<TaskObject> taskObjectList) {
        // 获取任务编码、处理人ID、处理人名称，逗号拼接
        // 逗号拼接占位符匹配对象.
        return taskObjectList.stream()
            .filter(x -> Objects.nonNull(x.getOwner()))
            .flatMap(taskObject -> {
                final UserInfo userInfo = taskObject.getOwner();
                return Stream.of(
                    Pair.of(TIID, taskObject.getTiid()),
                    Pair.of(USER_ID, userInfo.getUserId()),
                    Pair.of(USER_NAME, userInfo.getUserName())
                );
            })
            .collect(Collectors.collectingAndThen(
                    Collectors.groupingBy(Pair::getKey, Collectors.mapping(Pair::getValue, Collectors.toList())),
                    map -> Triple.of(
                        StringUtils.join(map.get(TIID), Constants.SPLIT_COMMA),
                        StringUtils.join(map.get(USER_ID), Constants.SPLIT_COMMA),
                        StringUtils.join(map.get(USER_NAME), Constants.SPLIT_COMMA)
                    )
                )
            );
    }

    /**
     * 保存草稿审批记录以及修改流程主表piid.
     * @param flowMainInfo 流程工单信息主表信息.
     * @param taskObjectList 任务实例对象（该对象本身不能为空，为空只能说明流程异常）.
     **/
    private void saveDraftFlowApproveInfo(final FlowMainInfo flowMainInfo, final List<TaskObject> taskObjectList) {
        final TaskObject taskObject = taskObjectList.get(0);
        final UserInfo userInfo = taskObject.getApplicant();
        final String userId = userInfo.getUserId();
        final String userName = userInfo.getUserName();
        final String deptName = userInfo.getDeptName();
        final String piid = taskObject.getPiid();

        // 获取任务编码、处理人ID、处理人名称，逗号拼接
        final Triple<String, String, String> triple = getTiidAndUserIdAndUserName(taskObjectList);

        final LocalDateTime createTime = flowMainInfo.getCreateTime();
        // 保存草稿审批记录（触发草稿没有任务编码tiid，默认piid）.
        final FlowApproveInfo approveInfo = new FlowApproveInfo();
        approveInfo.setPiid(piid);
        approveInfo.setTiid(piid);
        approveInfo.setTaskTag(getTopDeptDnByUserId(userId));
        approveInfo.setHandlerId(userId);
        approveInfo.setHandlerName(userName);
        approveInfo.setHandlerDept(deptName);
        approveInfo.setDecisionName(DRAFT_NODE_OPTION);
        approveInfo.setNextNodeId(DRAFT_NODE_ID);
        approveInfo.setNextNodeName(DRAFT_NODE_NAME);
        approveInfo.setNextHandlerId(triple.getMiddle());
        approveInfo.setNextHandlerName(triple.getRight());
        approveInfo.setNodeName(DRAFT_NODE_NAME);
        approveInfo.setNodeId(DRAFT_NODE_ID);
        approveInfo.setNotion(DRAFT_NODE_OPTION);
        approveInfo.setNextTiid(triple.getLeft());
        approveInfo.setCreateTime(createTime);
        approveInfo.setUpdateTime(createTime);
        insertFlowApproveInfo(approveInfo);

        // 保存草稿时需要修改流程主表piid.
        flowMainInfo.setPiid(piid);
        flowMainInfoService.updateFlowMainInfo(flowMainInfo);
    }

    /**
     * 起草.
     * @author YTG
     * @param startProcessForm 流程启动参数对象.
     * @return List<TaskObject>
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<TaskObject> draftTask(final StartProcessForm startProcessForm) {
        // 获取流程基本信息.
        final String applyId = startProcessForm.getApplyId();
        final FlowMainInfo flowMainInfo = flowMainInfoService.getInfoByWorkIdOrPiid(applyId, null);

        // 判断业务数据是否保存成功.
        if (StringUtils.isBlank(flowMainInfo.getPiid()) && StringUtils.isNotBlank(flowMainInfo.getWorkId())) {
            throw new BizException("操作失败，请先保存业务数据，applyId：" + applyId);
        }

        // 启动流程.
        startProcessForm.setBusinessProcess(flowMainInfo.getTemplateId()).setApplyTitle(flowMainInfo.getWorkName());
        final List<TaskObject> responseResult = workFlowService.startProcess(
            FlowProcessConverter.INSTANCE.formToStartProcess(startProcessForm));

        // 保存草稿审批记录.
        saveDraftFlowApproveInfo(flowMainInfo, responseResult);
        return responseResult;
    }

    /**
     * 创建阅办.
     * @param createReadsForm 创建阅办参数对象.
     * @return List<ReadObject>
     **/
    @Override
    public List<ReadObject> createReads(final CreateReadsForm createReadsForm) {
        // 创建待阅.
        final List<ReadObject> reads = workFlowService.createReads(
            FlowProcessConverter.INSTANCE.formToCreateReads(createReadsForm));
        // 创建待阅成功，就发生邮件.
        notifyService.sendReadObjectEmail(reads);
        return reads;
    }

    /**
     * 任务处理.
     * @param taskProcessForm 任务处理参数对象.
     * @return List<TaskObject>
     **/
    @Override
    public List<TaskObject> completeTask(final TaskProcessForm taskProcessForm) {
        return handleTask(taskProcessForm, false);
    }

    /**
     * 任务转交.
     * @param taskProcessForm 任务处理参数对象.
     * @return List<TaskObject>
     **/
    @Override
    public List<TaskObject> transferTask(final TaskProcessForm taskProcessForm) {
        return handleTask(taskProcessForm, true);
    }

    /**
     * 处理任务.
     * @param taskProcess 任务处理参数对象.
     * @param isTransfer 是否转交.
     * @return List<TaskObject>
     **/
    private List<TaskObject> handleTask(final TaskProcessForm taskProcess, final boolean isTransfer) {
        // 任务唯一标识.
        final String tiid = taskProcess.getTiid();
        // 保存业务数据标识.
        final String value = ExtendParamNameEnum.BUSINESS_DATA_SUBMISSION_ID.getValue();

        final FlowApproveInfo flowApproveInfo = flowApproveInfoMapper.selectFlowApproveInfoByPiidAndTiid(taskProcess.getPiid(), tiid);
        if (null == flowApproveInfo) {
            throw new BizException("请联系维护员，因其他工单转交到此工单，部分数据状态未修改成功，tiid：" + tiid);
        } else if (MapUtils.isEmpty(workFlowService.queryTaskExtendData(tiid, new String[]{value}))) {
            throw new BizException("操作失败，请先保存业务数据，tiid：" + tiid);
        }

        // 设置当前待办创建、提交时间.
        taskProcess.setCreateTime(flowApproveInfo.getUpdateTime());
        taskProcess.setModifyTime(LocalDateTime.now());

        // 判断是否执行提交与转交.
        final List<TaskObject> res = isTransfer
            ? workFlowService.transferTask(FlowProcessConverter.INSTANCE.formToCompleteTask(taskProcess))
            : workFlowService.completeTask(FlowProcessConverter.INSTANCE.formToCompleteTask(taskProcess));

        // 保存审批记录以及发送邮件
        saveApprove(FlowProcessConverter.INSTANCE.formToFlowApproveInfo(taskProcess), res);
        notifyService.sendTaskObjectEmail(res);
        return res;
    }
    /**
     * 保存审批记录.
     * @author YTG
     * @param flowApproveInfo 审批记录表.
     * @param taskObjectList 任务实例对象（该对象本身不能为空，为空只能说明流程异常）.
     * @return boolean
     **/

    private int saveApprove(final FlowApproveInfo flowApproveInfo, final List<TaskObject> taskObjectList) {
        // 获取当前登录人信息.
        final SysUser user = SecurityUtils.getLoginUser().getUser();
        flowApproveInfo.setHandlerName(user.getNickName());
        flowApproveInfo.setHandlerId(user.getUserName());

        // 获取任务编码、处理人ID、处理人名称，逗号拼接
        final Triple<String, String, String> triple = getTiidAndUserIdAndUserName(taskObjectList);
        flowApproveInfo.setNextHandlerName(triple.getRight());
        flowApproveInfo.setTaskTag(getTopDeptDn(user.getDeptDN()));
        flowApproveInfo.setNextHandlerId(triple.getMiddle());
        flowApproveInfo.setNextTiid(triple.getLeft());
        return insertFlowApproveInfo(flowApproveInfo);
    }
    /**
     * 获取一级部门DN. 需要通过uom 去获取
     * @param userId 用户ID. oaId
     * @return java.lang.String
     **/
    private String getTopDeptDnByUserId(final String userId) {
        return getTopDeptDn(UserBean.getInstanceByID(userId).getDepartmentDN());
    }
    private String getTopDeptDn(final String deptDn) {
        return CommonUtils.getTopDeptDn(deptDn);
    }

}
